#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif
#include <cr_section_macros.h>
#include <NXP/crp.h>
#include "pinconfig.h"
#include "find_uart_parameters.h"
#include "udpip.h"
__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// http://knowledgebase.nxp.com/showthread.php?p=10903
// http://cc.byexamples.com/2007/10/11/simple-callback-function/

void mycallback(unsigned char* msg, short len, unsigned char broadcast);

int send;
#define LONG_ARG_COMMANDE 32
char argument_commande[LONG_ARG_COMMANDE+1]; // +1 pour '\0'
char tampon[128];

volatile int messageDispo, messageIndex;
char *message;
#define MSG_LEN 256
void UART2_IRQHandler(void);

char buff[128];

#define GPS_BAUD_RATE 4800

int main(void)
{
	//unsigned char *mymac = '\00\11\11\c1\36\87';
	unsigned char  mymac[6]={'1','7','6','9','0','0'};
	unsigned long  myip= ((192<<0)+(168<<8)+(0<<16)+(9<<24));

	SystemInit();  // A documenter

	messageIndex = 0;
    message = (char*)malloc(sizeof(char)*MSG_LEN);
    // ! Allumer l'UART AVANT d'affecter les interruptions sinon crash sur HardFault_Handler...
	UART2PinsEnable(); // P0.10=TXD2, P0.11=RXD2
    NVIC_EnableIRQ(UART2_IRQn);
	// INT autorisee sur UART2
	LPC_UART2->IER |= (bit0); // Int Enable Register, bit0 = Received Data Available
    printf("-> interruption UART2 activee\n");
	set_optimal_uart_config_for_cclk(SystemCoreClock, GPS_BAUD_RATE);

	send = 0;
	printf("Activation UDP \n");
	udpipInit(mymac, myip);
	short idx = 1;  // 0 a 3
	unsigned short port = 54321;
	udpipSetService(idx, port, &mycallback);
	udpipSaveRemoteForService(idx);
	udpipSetBroadcastForService(idx, port);
	
	// Enter an infinite loop, just incrementing a counter
	volatile static int i = 0, msgcount = 1 ;
	while(1)
	{
		// UDP
		udpipWork();
		// RS232
		if ( messageDispo == 1 )
		{
		  sprintf(buff,"%d-%s",msgcount, message);
		  printf("Un Message a traiter : [%s], L=%d\n", buff, strlen(buff));
		  // Renvoie via UDP
  		   udpipSend(1, buff, strlen(buff));
  		   msgcount++;
		  messageDispo = 0;
		}
		i++ ;
	}
	return 0 ;
}

// 100 commandes possible: de 00 a 98
void mycallback(unsigned char* msg, short len, unsigned char broadcast)
{
//printf("IN CALL BACK !!!\n")
	int commande = 99;
	char cmde[3];
	msg[len] = '\0';
	argument_commande[0] = '\0';
	// les 2 premier caracteres sont la commande, ex: "05xyz" => commande 05
	// conversion de la chaine en entier
	// si longueur < 2 -> rejet
	if ( len < 2 )
	{
	  printf("Commande invalide!\n");
      return;
	}
	// verifie si les 2 premiers caracteres sont bien un chiffre et extrait la commande
	if (( msg[0] < '0' || msg[0] > '9') || ( msg[1] < '0' || msg[1] > '9' ))
	{
		printf("Les 2 premiers caracteres d'une commande doivent etre des chiffres!\n");
		return;
	}
	cmde[0] = msg[0];
	cmde[1] = msg[1];
	cmde[2] = '\0';
	commande = atoi(cmde);
	// Argument a la commande ?
	if ( len > 2 )
	{
	 if ( len > LONG_ARG_COMMANDE )
	  len = LONG_ARG_COMMANDE; // evite tout depassement d'espace alloue
	 memcpy(argument_commande, msg+2, len);
	 argument_commande[len] = '\0';
	}
	else
	 argument_commande[0] = '\0';

	// Accuse de reception de la commande -> TODO accuse de traitement de la commande
	printf("-> Commande recue = [%d], Argument = [%s]\n", commande, argument_commande);
	sprintf(tampon, "Commande recue=[%d], argument=[%s]", commande, argument_commande);
	udpipSend(1, tampon, strlen(tampon));

	// traitement commandes
	switch( commande )
	{
		case 0 	: printf("e.g: RAZ systeme\n"); break;
		case 1	: printf("e.g: Prechauffage\n"); break;
		case 2	: printf("e.g: Demarrage moteur\n");break;
		case 3	: printf("e.g: Arret moteur\n");break;
		case 4	: printf("e.g: Allumage phares\n");break;
		case 5	: break;
		case 6	: break;
		case 7	: break;
		case 8	: break;
		case 9	: break;
		case 10	: break;
		case 11	: break;
		case 12	: break;
		default : /* commande non traitee */ break;
	}
}

void udpipActivity100MOn(void)
{
	printf("UDP 100M\n");
}

void udpipActivity10MOn(void)
{
	printf("UDP 10M\n");
}

void udpipActivityOff(void)
{
	printf("UDP OFF\n");
}

void UART2_IRQHandler(void)
{
  char car;
	//printf("UART2 INT!\n");  // ! semihosting project
	//LPC_UART2->IER &= ~(bit0); // Int Off -> ! alors plus d'interruption possible
	switch( (LPC_UART2->IIR & (bit1|bit2|bit3)) )   // Int Identification register
	{
	   case (bit1|bit2)	:	printf("RX line Status/Error\n");
	   	   	   	   	   	   	LPC_UART2->LSR;    // La lecture de LSR provoque le Reset de l'interrupt
	   	   	   	   	   	   	// Todo, traiter le probleme
	   	   	   	   	   	    break;
	   case (bit2)		:	//printf("RX Data Available\n");
	   	   	   	   	   	    // LA LECTURE DE RBR RESET L'INTERRUPT
	   	   	   	   	   	    car = LPC_UART2->RBR;
	   	   	   	   	   	   	//printf("Receive Buffer Register = [%c]\n", car);
	   	   	   	   	   	   	if ( car == '\n' || car == '\r' )
	   	   	   	   	   	   	{
	   	   	   	   	   	   		messageDispo = 1;
	   	   	   	   	   	   		messageIndex = 0;
	   	   	   	   	   	   	}
	   	   	   	   	   	   	else
	   	   	   	   	   	   	{
	   	   	   	   	   	   		*(message+messageIndex) = car;
	   	   	   	   	   	   		messageIndex++;
	   	   	   	   	   	   		*(message+messageIndex) = '\0';
	   	   	   	   	   	   	}
	   	   	   	   	   	   	break;
	   case (bit2|bit3)	:	//printf("Character Time Out\n");
	   	   	    			// LA LECTURE DE RBR RESET L'INTERRUPT
	   	   	   	   	   	    car = LPC_UART2->RBR;
	   	   	   				//printf("Receive Buffer Register = [%c]\n", car);
	   	   	   				if ( car == '\n' || car == '\r' )
	   	   	   				{
	   	   	   					messageDispo = 1;
	   	   	   					messageIndex = 0;
	   	   	   				}
	   	   	   				else
	   	   	   				{
	   	   	   					*(message+messageIndex) = car;
	   	   	   					messageIndex++;
	   	   	   					*(message+messageIndex) = '\0';
	   	   	   				}
	   	   	   	   	   	   	break;
	   case (bit1)		:	printf("THRE\n");
	   	   	   	   	   	   	LPC_UART2->IIR; // La lecture de IIR provoque Reset de l'interrupt ou write sur THR (deja dans le switch)
	   	   	   	   	   	   	// TODO
                            // ....
	   	   	   	   	   	   	break;
	}
	//NVIC_ClearPendingIRQ(UART2_IRQn);
	//LPC_UART2->IE
}

